package socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.UUID;

/**
 * 图形化客户端
 *
 * 客户端提示词:
 * 基于上述代码实现图形化的客户端，要求窗口中包含一个文本域用来展示服务端发送过来的聊天消息。
 * 在文本域下方生成一个输入框，用来获取用户输入的聊天信息，在输入框右侧生成一个按钮，
 * 按钮上显示"发送"两个字。并且当点击按钮后可以将输入框中输入的内容发送给服务端。
 *
 *
 * 用豆包AI辅助补完功能步骤:
 * 1:先将我们的代码贴到AI中
 * 2:输入提示词内容
 * 3:将生成后的代码替换回来。如果AI将类名进行了修改，我们也可以延用他的类名，此时我们只需要在
 *   我们的包中创建对应的类，然后将代码粘贴进去即可。下面的代码就是
 *
 *
 */
public class Client extends JFrame {
    private Socket socket;
    private JTextArea chatArea;      // 显示聊天记录的文本域
    private JTextField inputField;   // 输入消息的文本框
    private JButton sendButton;      // 发送按钮
    private String clientId;         // 客户端唯一标识，用于区分自己和他人的消息

    public Client() {
        // 生成客户端唯一标识
        clientId = UUID.randomUUID().toString();

        // 初始化UI
        initUI();

        try {
            System.out.println("正在链接服务端...");
            socket = new Socket("localhost", 8088);
            // socket = new Socket("192.168.1.3", 8088);
            System.out.println("链接服务端成功!");

            // 启动线程接收服务器消息
            new Thread(new MessageReceiver()).start();

        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "连接服务器失败: " + e.getMessage(),
                    "错误", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 初始化用户界面
     */
    private void initUI() {
        setTitle("聊天室客户端");
        setSize(500, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null); // 窗口居中

        // 创建面板和组件
        JPanel mainPanel = new JPanel(new BorderLayout());

        // 聊天记录区域
        chatArea = new JTextArea();
        chatArea.setEditable(false); // 只读，不能编辑
        chatArea.setLineWrap(true);  // 自动换行
        JScrollPane scrollPane = new JScrollPane(chatArea);
        mainPanel.add(scrollPane, BorderLayout.CENTER);

        // 输入和发送区域
        JPanel inputPanel = new JPanel(new BorderLayout(5, 5));
        inputField = new JTextField();
        sendButton = new JButton("发送");

        inputPanel.add(inputField, BorderLayout.CENTER);
        inputPanel.add(sendButton, BorderLayout.EAST);

        // 添加边距
        inputPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        mainPanel.add(inputPanel, BorderLayout.SOUTH);

        // 添加到窗口
        add(mainPanel);

        // 注册事件监听
        sendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                sendMessage();
            }
        });

        // 按回车键发送消息
        inputField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                sendMessage();
            }
        });
    }

    /**
     * 发送消息到服务器
     * 消息格式: [clientId]|message
     */
    private void sendMessage() {
        String message = inputField.getText().trim();
        if (message.isEmpty()) {
            return; // 空消息不发送
        }

        try {
            if (socket != null && !socket.isClosed()) {
                OutputStream out = socket.getOutputStream();
                // 消息格式: [clientId]|message，用于服务端识别发送者
                String fullMessage = clientId + "|" + message;
                byte[] data = fullMessage.getBytes(StandardCharsets.UTF_8);

                // 先发送消息长度，再发送消息内容
                out.write(data.length);
                out.write(data);
                out.flush();

                // 在聊天区域显示自己发送的消息
                chatArea.append("我: " + message + "\n");
                // 清空输入框
                inputField.setText("");
                // 滚动到底部
                chatArea.setCaretPosition(chatArea.getDocument().getLength());
            }
        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "发送消息失败: " + e.getMessage(),
                    "错误", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 接收服务器消息的线程
     */
    private class MessageReceiver implements Runnable {
        @Override
        public void run() {
            try {
                InputStream in = socket.getInputStream();
                int len;

                while ((len = in.read()) != -1) {
                    byte[] data = new byte[len];
                    in.read(data);
                    String fullMessage = new String(data, StandardCharsets.UTF_8);

                    // 解析消息，分离clientId和实际消息内容
                    String[] parts = fullMessage.split("\\|", 2);
                    if (parts.length == 2) {
                        String senderId = parts[0];
                        String message = parts[1];

                        // 只显示他人发送的消息，忽略自己发送的消息（因为已经显示过）
                        if (!senderId.equals(clientId)) {
                            // 在EDT线程中更新UI
                            SwingUtilities.invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    chatArea.append("他人: " + message + "\n");
                                    chatArea.setCaretPosition(chatArea.getDocument().getLength());
                                }
                            });
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        JOptionPane.showMessageDialog(Client.this, "与服务器断开连接: " + e.getMessage(),
                                "连接断开", JOptionPane.WARNING_MESSAGE);
                    }
                });
            } finally {
                try {
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        // 在EDT线程中启动UI
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Client().setVisible(true);
            }
        });
    }
}